﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Threading;
using System.Drawing.Imaging;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace console_pictures_viewer
{
    /// <summary>
    /// Pictures Viewer cut size of the image by two times and change its quality
    /// </summary>
    public partial class PicturesViewer : Form
    {
        public PicturesViewer()
        {
            InitializeComponent();
        }

        private ProgressBarDialog dialog = new ProgressBarDialog();

        private List<FileName> files = new List<FileName>();

        private string directoryForSave = null; // имя директории для сохранения измененных файлов

        private int currentFileIndex = -1; // номер текущего изображения в массиве файлов

        private void ChooseFilesButtonClick(object sender, EventArgs e)
        {
            if (DialogResult.Cancel != openFileDialog.ShowDialog(this))
            {
                string[] full_file_names = openFileDialog.FileNames;
                for (int i = 0; i < full_file_names.Length; i+=1)
                {
                    files.Add(new FileName(full_file_names[i]));
                }                
                PicturesBox.Image = Image.FromFile(files[0].GetFullName());
                this.Text = "Изображения " + files[0].GetNameWithExtension();

                // делаем контролы видимыми
                currentFileIndex = 0;
                BackButton.Enabled = true;
                ForwardButton.Enabled = true;
                ChooseSaveDirectoryButton.Enabled = true;
            }
        }

        private void BackButtonClick(object sender, EventArgs e)
        {
            if (currentFileIndex > 0)
            {// если сейчас отображается файл и он не первый в коллекции 
                // (т.к. нельзя осуществить действие "Назад" для первого элемента)
                currentFileIndex -= 1;
                PicturesBox.Image = Image.FromFile(files[currentFileIndex].GetFullName());
                this.Text = "Изображения " + files[currentFileIndex].GetNameWithExtension();
            }
        }

        private void ForwardButtonClick(object sender, EventArgs e)
        {
            if (currentFileIndex < files.Count() - 1)
            {
                currentFileIndex += 1;
                PicturesBox.Image = Image.FromFile(files[currentFileIndex].GetFullName());
                this.Text = "Изображения " + files[currentFileIndex].GetNameWithExtension();
            }
        }

        private void ChangeAllSizeButtonClick(object sender, EventArgs e)
        {
            if (DialogResult.Yes == 
                MessageBox.Show(this, 
                "Хотите ли вы изменить размер всех выбраных фотографий? (" + files.Count().ToString() + ")", 
                "Предупреждение", 
                MessageBoxButtons.YesNo))
            {
                this.Enabled = false;
                // обновляющийся диалог в параллельном потоке
                backgroundWorker.DoWork += new DoWorkEventHandler(ShowProgressDialog);
                backgroundWorker.RunWorkerAsync();

                // обрабатываем фотографии
                for (int i = 0; i < files.Count(); i++)
                {
                    this.Refresh();
                    Bitmap oldImage = new Bitmap(files[i].GetFullName());
                    float width = oldImage.Width / 2;
                    float height = oldImage.Height / 2;
                    
                    Bitmap newImage = new Bitmap ((int) width, (int) height);
                    Graphics grPhoto = Graphics.FromImage(newImage);
                    grPhoto.Clear(System.Drawing.Color.FromArgb(0, 255, 255, 255));

                    grPhoto.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                    grPhoto.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                    grPhoto.DrawImage(oldImage, 0, 0, width, height);
                    grPhoto.Flush();
                    
                    if (i == currentFileIndex)
                    {// только для текущей показываемой картинки
                        PicturesBox.Image.Dispose(); // освободим картинку, показываемую программно в данный момент
                    }

                    // получим дату создания снимка   
                    PropertyItem[] props = oldImage.PropertyItems;
                    string shotDate = "";
                    foreach (PropertyItem prop in props)
                    {
                        if (prop.Id == 36868 && prop.Type == 2)
                        {
                            shotDate = Encoding.ASCII.GetString(prop.Value,0,prop.Len-1);
                        }
                    }
                    oldImage.Dispose(); // освободить изображение из обработчика
                    
                    shotDate = DateInStringFormatToFileViableString(shotDate);// изменить строку даты на строку, 
                                                           //которую можно использовать в названии файла(без запрещенных символов)

                    String fileToDelete = directoryForSave + files[i].GetNameWithExtension();
                    File.Delete(fileToDelete); // удаляем старый файл если он уже есть в каталоге directoryForSave
                    String fileToSave = directoryForSave + "\\" + shotDate + " " + files[i].GetNameWithExtension();
                    newImage.Save(fileToSave, System.Drawing.Imaging.ImageFormat.Jpeg); // сохраняем новый файл в нужном формате

                    // изменим массив выбранных путей до фотографий на новый путь, чтобы корректно отображать фотографии в pictureBox
                    files[i] = new FileName(directoryForSave + "\\" + shotDate + " " + files[i].GetNameWithExtension());

                    if (i == currentFileIndex)
                    {// только для текущей показываемой картинки
                        PicturesBox.Image = Image.FromFile(files[i].GetFullName()); // установим новую картинку - измененную старую
                        this.Text = "Изображения " + files[currentFileIndex].GetNameWithExtension(); // изменим заголовок окна на новый
                    }

                    ChangeProgressDialog(i + 1, files.Count());                                      
                }
                this.Enabled = true; // сделать форму активной
            }        
        }

        delegate void ChangeProgressDialogCallback(int current, int summary);
        private void ChangeProgressDialog(int current, int summary)
        {
            if (dialog.InvokeRequired)
            {
                ChangeProgressDialogCallback callback = new ChangeProgressDialogCallback(ChangeProgressDialog);
                dialog.Invoke(callback, current, summary);
            }
            else
            {
                dialog.ChangeProgress(current, summary);
            }
        }
        
        private void pictureBox1_MouseWheel(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            int abc = e.Delta;
        }

        private void ChooseDirectoryButtonClick(object sender, EventArgs e)
        {
            folderBrowserDialog.SelectedPath = files[0].GetFullName();
            if (DialogResult.Cancel != folderBrowserDialog.ShowDialog(this))
            {
                directoryForSave = folderBrowserDialog.SelectedPath;
                ChoseDirectoryText.Text = directoryForSave;
                ToolTip toolTipForTextBox1 = new ToolTip();
                toolTipForTextBox1.SetToolTip(this.ChoseDirectoryText, directoryForSave);

                ChangeAllSizeButton.Enabled = true;
            }
        }

        private string DateInStringFormatToFileViableString(string str)
        {
            string date_to_file_str = str;
            date_to_file_str = date_to_file_str.Replace(':', '_');
            date_to_file_str = date_to_file_str.Replace('\\', '_');
            date_to_file_str = date_to_file_str.Replace('/', '_');
            date_to_file_str = date_to_file_str.Replace('<', '_');
            date_to_file_str = date_to_file_str.Replace('>', '_');
            date_to_file_str = date_to_file_str.Replace('*', '_');
            date_to_file_str = date_to_file_str.Replace('?', '_');
            return date_to_file_str;
        }

        delegate void ShowProgressDialogCallback(object sender, DoWorkEventArgs args);
        private void ShowProgressDialog(object sender, DoWorkEventArgs args)
        {
            if (dialog.InvokeRequired)
            {
                ShowProgressDialogCallback callback = new ShowProgressDialogCallback(ShowProgressDialog);
                dialog.Invoke(callback, sender, args);
            }
            else
            {
                dialog = new ProgressBarDialog();
                dialog.ShowDialog();
            }
        }

        delegate void ProgressChangeFiredCallback(object sender, ProgressChangedEventArgs args);
        private void ProgressChangeFired(object sender, ProgressChangedEventArgs args)
        {
            ProgressChangeArgument arg = args.UserState as ProgressChangeArgument;
            if (dialog.InvokeRequired)
            {
                ProgressChangeFiredCallback callback = new ProgressChangeFiredCallback(ProgressChangeFired);
                this.Invoke(callback, sender, args);
            }
            else
            {
                dialog.ChangeProgress(arg.current, arg.summary);
            }            
        }

    }
}
